home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / xpk_source / xpkmaster / xpkmaster.c < prev    next >
C/C++ Source or Header  |  1998-08-27  |  20KB  |  724 lines

  1. #ifndef XPKMASTER_XPKMASTER_C
  2. #define XPKMASTER_XPKMASTER_C
  3.  
  4. /* Routinesheader
  5.  
  6.     Name:        xpkmaster.c
  7.     Main:        xpkmaster
  8.     Versionstring:    $VER: xpkmaster.c 1.14 (28.08.1998)
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    the main xpk functions
  12.  
  13.  1.0   09.10.96 : first real version
  14.  1.1   27.12.96 : removed 1.3 specific functions
  15.  1.2   10.01.97 : corrected XpkPack's abort
  16.  1.3   11.01.97 : corrected mem bug (reported by Laurent Kempe)
  17.  1.4   30.01.97 : hopefully fixed mem bug finally
  18.  1.5   31.01.97 : bug still occured
  19.  1.6   01.03.97 : added NoPack stuff to XpkWrite and XpkPack
  20.  1.7   24.03.97 : fixed XpkPack
  21.  1.8   25.03.97 : added AutoPasswd
  22.  1.9   28.03.97 : moved autopassword into xpkopen
  23.  1.10  01.04.97 : fixed NoPack error
  24.  1.11  19.12.97 : added xfdmaster support, made MBUG defines
  25.  1.12  09.01.98 : better passkey handling
  26.  1.13  21.02.98 : uses new style register definition
  27.  1.14  26.08.98 : lonely XpkWrite fixes
  28. */
  29.  
  30. /**************************************************/
  31. #ifdef __MAXON__                /**/
  32.   #define MBUGDEF    ULONG maxon_bug;    /**/
  33.   #define MBUG        maxon_bug = (ULONG)    /**/
  34. #else                        /**/
  35.   #define MBUG                      /**/
  36.   #define MBUGDEF                /**/
  37. #endif                        /**/
  38. /**************************************************/
  39.  
  40. #include <proto/exec.h>
  41. #include <proto/intuition.h>
  42. #include <proto/dos.h>
  43. #include <proto/utility.h>
  44. #include <proto/xpkmaster.h>
  45. #include <proto/xfdmaster.h>
  46. #include <proto/xpksub.h>
  47. #include <exec/types.h>
  48. #include <exec/memory.h>
  49. #include <exec/tasks.h>
  50. #include <dos/dos.h>
  51. #include "xpkmaster.h"
  52. #include "texts.h"
  53.  
  54. #ifdef USE_POWERPACKER
  55.   #include <proto/powerpacker.h>
  56.   #include <libraries/ppbase.h>
  57. #endif
  58.  
  59. #ifdef SUPPORT_A4
  60.   LONG XpkOpenA4NAME(struct XpkFib **xfh, struct TagItem *tags, ULONG a4);
  61.   #ifdef __SASC
  62.     #pragma libcall XpkBase XpkOpenA4NAME 036 C9803
  63.   #else
  64.     #pragma amicall(XpkBase,0x36,XpkOpenA4NAME(a0,a1,a4))
  65.   #endif
  66. #else
  67.   #define XpkOpenA4NAME XpkOpen
  68. #endif
  69.  
  70. /**************************************************************************
  71.  *
  72.  *   XpkPack() - pack a file
  73.  *
  74.  */
  75.  
  76. ASM(LONG) LIBXpkPack(REG(a0, struct TagItem *tags) A4PROTO)
  77. {
  78.   struct XpkBuffer *xbuf = 0;
  79.   STRPTR buf;
  80.   LONG totlen, res, chunklen;
  81.  
  82.   if(!FindTagItem(XPK_PackMethod, tags))
  83.     return XPKERR_BADPARAMS;
  84.  
  85.   if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
  86.     return res;
  87.  
  88.   if((totlen = xbuf->xb_InLen) == 0xFFFFFFFF)
  89.   {
  90.     xbuf->xb_Result = XPKERR_BADPARAMS;
  91.     return XpkClose((struct XpkFib *) xbuf);
  92.   }
  93.  
  94.   CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */
  95.  
  96.   xbuf->xb_Prog.xp_Type = XPKPROG_START;
  97.   xbuf->xb_Prog.xp_ULen = totlen;
  98.   if(callprogress(xbuf))
  99.     return XpkClose((struct XpkFib *) xbuf);
  100.  
  101.   while(totlen > 0)
  102.   {
  103.     chunklen = xbuf->xb_Fib.xf_NLen;
  104.  
  105.     if(!(buf = (STRPTR) hookread(xbuf, XIO_READ, NULL, chunklen)))
  106.       break;
  107.  
  108.     if(XpkWrite((struct XpkFib *) xbuf, buf, chunklen))
  109.       break;
  110.  
  111.     totlen -= chunklen;
  112.  
  113.     xbuf->xb_Prog.xp_Type = XPKPROG_MID;    /* Progress report     */
  114.     xbuf->xb_Prog.xp_UCur += chunklen;
  115.     xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
  116.     if(callprogress(xbuf))
  117.       return XpkClose((struct XpkFib *) xbuf);
  118.   }
  119.  
  120.   if(xbuf->xb_Prog.xp_Type)
  121.   {
  122.     xbuf->xb_Prog.xp_Type = XPKPROG_END;
  123.     xbuf->xb_Prog.xp_CCur += xbuf->xb_Headers.h_LocSize;
  124.     xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ?
  125.       strings[TXT_ABORTED] : xbuf->xb_LastMsg;
  126.     callprogress(xbuf);     /* Call the hook one last time */
  127.   }
  128.  
  129.   return XpkClose((struct XpkFib *) xbuf);
  130. }
  131.  
  132. /*********************************************************************
  133.  *
  134.  * XpkUnpack - unpack a file
  135.  *
  136.  */
  137.  
  138. ASM(LONG) LIBXpkUnpack(REG(a0, struct TagItem *tags) A4PROTO)
  139. {
  140.   struct XpkBuffer *xbuf = NULL;
  141.   STRPTR pointer;
  142.   LONG len, res;
  143.  
  144. #ifdef DEBUG
  145.   DebugRunTime("XpkUnpack");
  146. #endif
  147.  
  148.   if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
  149.     return res;
  150.  
  151.   if(xbuf->xb_Flags & XMF_PACKING)
  152.   {
  153.     xbuf->xb_Result = XPKERR_BADPARAMS;
  154.     goto Abort;
  155.   }
  156.  
  157.   CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */
  158.  
  159.   xbuf->xb_Prog.xp_Type = XPKPROG_START;    /* Initialize progress */
  160.   xbuf->xb_Prog.xp_ULen = xbuf->xb_Fib.xf_ULen;
  161.   if(callprogress(xbuf))
  162.     goto Abort;
  163.  
  164.   if(!hookwrite(xbuf, XIO_TOTSIZE, NULL, xbuf->xb_Fib.xf_ULen + XPK_MARGIN))
  165.   {
  166. #ifdef DEBUG
  167.     DebugError("XpkUnpack: XIO_TOTSIZE failed");
  168. #endif
  169.     goto Abort;
  170.   }
  171.  
  172.   if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, 0, xbuf->xb_Fib.xf_NLen)))
  173.   {
  174. #ifdef DEBUG
  175.     DebugError("XpkUnpack: XIO_GETBUF failed (a)");
  176. #endif
  177.     goto Abort;
  178.   }
  179.  
  180. #ifdef DEBUG
  181.   if(xbuf->xb_Result)
  182.     DebugError("XpkUnpack: failure before unpackloop");
  183. #endif
  184.  
  185.   while((len = XpkRead((struct XpkFib *) xbuf, pointer, xbuf->xb_Fib.xf_NLen)) > 0)
  186.   {
  187.     if(!hookwrite(xbuf, XIO_WRITE, pointer, len))
  188.     {
  189. #ifdef DEBUG
  190.       DebugError("XpkUnpack: XIO_WRITE failed");
  191. #endif
  192.       goto Abort;
  193.     }
  194.  
  195.     xbuf->xb_Prog.xp_Type = XPKPROG_MID;    /* Progress report     */
  196.     xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
  197.     xbuf->xb_Prog.xp_UCur = xbuf->xb_Fib.xf_UCur;
  198.     if(callprogress(xbuf))
  199.       goto Abort;
  200.  
  201.     if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, xbuf->xb_Fib.xf_NLen)))
  202.     {
  203. #ifdef DEBUG
  204.       DebugError("XpkUnpack: XIO_GETBUF failed (b)");
  205. #endif
  206.       goto Abort;
  207.     }
  208.   }
  209.  
  210.   xbuf->xb_Result = len;
  211. #ifdef DEBUG
  212.   if(xbuf->xb_Result)
  213.     DebugError("XpkUnpack: XpkRead failed with %ld", xbuf->xb_Result);
  214. #endif
  215.  
  216.   if(xbuf->xb_Prog.xp_Type)
  217.   {
  218.     xbuf->xb_Prog.xp_Type = XPKPROG_END;
  219.     xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ? strings[TXT_ABORTED] : xbuf->xb_LastMsg;
  220.     callprogress (xbuf);    /* Call the hook one last time */
  221.   }
  222. Abort:
  223.   return XpkClose((struct XpkFib *) xbuf);
  224. }
  225.  
  226. /*********************************************************************
  227.  *
  228.  * XpkOpen - open a file for packing/unpacking
  229.  *
  230.  */
  231.  
  232. ASM(LONG) LIBXpkOpen(REG(a0, struct XpkBuffer **xbufp),
  233.     REG(a1, struct TagItem *tags) A4PROTO)
  234. {
  235. #if defined(DEBUG) && defined(SUPPORT_A4)
  236.   DebugRunTime("XpkOpen: A4 = %ld", a4);
  237. #elif defined(DEBUG)
  238.   DebugRunTime("XpkOpen");
  239. #endif
  240.   return xpkopen(xbufp, tags, 0 A4SUPP);
  241. }
  242.  
  243. /**************************************************************************
  244.  *
  245.  *   XpkExamine() - inspect a compressed file
  246.  *
  247.  */
  248.  
  249. ASM(LONG) LIBXpkExamine(REG(a0, struct XpkFib *fib),
  250.     REG(a1, struct TagItem *tags) A4PROTO)
  251. {
  252.   struct XpkBuffer *dummy;
  253.   LONG res;
  254.  
  255. #if defined(DEBUG) && defined(SUPPORT_A4)
  256.   DebugRunTime("XpkExamine: A4 = %ld", a4);
  257. #elif defined(DEBUG)
  258.   DebugRunTime("XpkExamine");
  259. #endif
  260.  
  261.   if((res = xpkopen(&dummy, tags, 1 A4SUPP)))
  262.     return res;
  263.  
  264.   CopyMem(dummy, fib, sizeof(struct XpkFib));
  265.   /* copies the entries of XpkFib
  266.      *fib = dummy->Fib works too, but calls it's own copy-function */
  267.  
  268.   return XpkClose((struct XpkFib *) dummy);
  269. }
  270.  
  271. /**************************************************************************
  272.  *
  273.  *   XpkRead() - read one chunk from a compressed file
  274.  *
  275.  */
  276.  
  277. ASM(LONG) LIBXpkRead(REG(a0, struct XpkBuffer *xbuf), REG(a1, STRPTR buf),
  278.     REG(d0, ULONG len))
  279. {
  280.   MBUGDEF
  281.  
  282. #ifdef DEBUG
  283.   DebugRunTime("XpkRead: buf %08lx, size %ld", buf, len);
  284. #endif
  285.  
  286.   if(!xbuf)
  287.     return XPKERR_NOFUNC;
  288.  
  289.   if(xbuf->xb_Flags & XMF_EOF)
  290.     return 0;
  291.  
  292.   switch(xbuf->xb_Format) 
  293.   {
  294.     /*********************** Unpack standard XPK *******************/
  295.   case XPKMODE_UPSTD:
  296.     {
  297.       struct XpkSubParams *xpar;
  298.       struct Library *XpkSubBase = xbuf->xb_SubBase;
  299.       XpkChunkHeader *lochdr = &(xbuf->xb_Headers.h_Loc);
  300.       LONG ulen, clen, rclen, lochdrsize = xbuf->xb_Headers.h_LocSize;
  301.       ULONG csum;
  302.  
  303.       if(lochdr->xch_Word.xchw_Type == XPKCHUNK_END)
  304.         return 0;
  305.  
  306.       if((MBUG hchecksum((STRPTR) lochdr, lochdrsize)))
  307.       {
  308. #ifdef DEBUG
  309.         DebugError("XpkRead: hchecksum(,%ld) failed", lochdrsize);
  310. #endif
  311.         return(xbuf->xb_Result = XPKERR_CHECKSUM);
  312.       }
  313.  
  314.       if(xbuf->xb_Headers.h_Glob.xsh_Flags & XPKSTREAMF_LONGHEADERS)
  315.         ulen = lochdr->xch_Long.xchl_ULen, clen = lochdr->xch_Long.xchl_CLen;
  316.       else
  317.         ulen = lochdr->xch_Word.xchw_ULen, clen = lochdr->xch_Word.xchw_CLen;
  318.       rclen = ROUNDLONG(clen);
  319.  
  320.       if(lochdr->xch_Word.xchw_Type == XPKCHUNK_RAW)
  321.       {
  322.         if(!(MBUG hookread(xbuf, XIO_READ, buf, rclen + lochdrsize)))
  323.       return xbuf->xb_Result;
  324.  
  325.         if(!(xbuf->xb_Flags & XMF_NOCRC))
  326.       if((csum=cchecksum((ULONG *) buf, rclen >>2)) != lochdr->xch_Word.xchw_CChk)
  327.       {
  328. #ifdef DEBUG
  329.         DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >> 2, csum, (ULONG) lochdr->xch_Word.xchw_CChk);
  330. #endif
  331.         return (xbuf->xb_Result = XPKERR_CHECKSUM);
  332.           }
  333.  
  334.         CopyMem(buf + rclen, lochdr, lochdrsize);
  335.       }
  336.       else if(lochdr->xch_Word.xchw_Type == XPKCHUNK_PACKED)
  337.       {
  338.         xpar = &xbuf->xb_PackParam;
  339.         if(!(xpar->xsp_InBuf = hookread(xbuf, XIO_READ, NULL, rclen + lochdrsize)))
  340.       return xbuf->xb_Result;
  341.  
  342.         if(!(xbuf->xb_Flags & XMF_NOCRC))
  343.       if((csum=cchecksum((ULONG *)xpar->xsp_InBuf, rclen >> 2)) != lochdr->xch_Word.xchw_CChk)
  344.       {
  345. #ifdef DEBUG
  346.         DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >>2 , csum, (ULONG) lochdr->xch_Word.xchw_CChk);
  347. #endif
  348.         return (xbuf->xb_Result = XPKERR_CHECKSUM);
  349.           }
  350.         xbuf->xb_Flags |= XMF_INITED;
  351.  
  352.         xpar->xsp_InLen = clen;
  353.         xpar->xsp_OutLen = ulen;
  354.         xpar->xsp_OutBuf = buf;
  355.         xpar->xsp_OutBufLen = ulen;
  356.         xpar->xsp_Number = 0;
  357.         xpar->xsp_Password = xbuf->xb_Password;
  358.         xpar->xsp_LibVersion = xbuf->xb_Headers.h_Glob.xsh_SubVrs;
  359.  
  360.         if((xbuf->xb_Result = XpksUnpackChunk(xpar)))
  361.       return xbuf->xb_Result;
  362.  
  363.         CopyMem((STRPTR) xpar->xsp_InBuf + rclen, lochdr, lochdrsize);
  364.       }
  365.       else
  366.         return (xbuf->xb_Result = XPKERR_CORRUPTPKD);
  367.  
  368.       updatefib(xbuf);
  369.       return ulen;
  370.     }
  371. #ifdef USE_POWERPACKER
  372.     /********************* Unpack powerpacked file ****************/
  373.   case XPKMODE_UPPP:
  374.     {
  375.       struct Library *PPBase = xbuf->xb_SubBase;
  376.       STRPTR inbuf, inbufend;
  377.  
  378.       if(!(inbuf = (STRPTR) hookread(xbuf, XIO_READ, NULL, xbuf->xb_InLen - 4)))
  379.         return xbuf->xb_Result;
  380.       inbufend = inbuf + xbuf->xb_InLen - 4;
  381.  
  382.       ppDecrunchBuffer(inbufend, buf, (ULONG *) inbuf, DECR_NONE);
  383.  
  384.       xbuf->xb_Fib.xf_CCur = xbuf->xb_InLen;
  385.       xbuf->xb_Fib.xf_UCur = xbuf->xb_Fib.xf_ULen;
  386.       xbuf->xb_Fib.xf_NLen = 0;
  387.       xbuf->xb_Flags |= XMF_EOF;
  388.  
  389.       return (LONG) xbuf->xb_Fib.xf_ULen;
  390.     }
  391. #endif /* USE_POWERPACKER */
  392.  
  393.   /**************************** xfdmaster file **************************/
  394.   case XPKMODE_UPXFD:
  395.     {
  396.       struct xfdMasterBase *xfdMasterBase = (struct xfdMasterBase *) xbuf->xb_SubBase;
  397.       struct xfdBufferInfo *xbi = xbuf->xb_xfd;
  398.  
  399.       xbi->xfdbi_Flags = XFDFF_USERTARGET;
  400.       xbi->xfdbi_UserTargetBuf = buf;
  401.       xbi->xfdbi_UserTargetBufLen = len;
  402.       if((xbuf->xb_Fib.xf_Flags & XPKFLAGS_KEY32) &&
  403.       (xbuf->xb_Flags & XMF_KEY32))
  404.         xbi->xfdbi_Special = &xbuf->xb_PassKey32;
  405.       else if((xbuf->xb_Fib.xf_Flags & XPKFLAGS_KEY16) &&
  406.       (xbuf->xb_Flags & XMF_KEY16))
  407.         xbi->xfdbi_Special = &xbuf->xb_PassKey16;
  408.       else if(xbuf->xb_Fib.xf_Flags & XPKFLAGS_PASSWORD)
  409.         xbi->xfdbi_Special = xbuf->xb_Password;
  410.  
  411.       if(!xfdDecrunchBuffer(xbi))
  412.       {
  413.         switch(xbi->xfdbi_Error)
  414.         {
  415.         case XFDERR_NOMEMORY: xbuf->xb_Result = XPKERR_NOMEM; break;
  416.         case XFDERR_WRONGPASSWORD: case XFDERR_WRONGKEY:
  417.           xbuf->xb_Result = XPKERR_WRONGPW; break;
  418.         case XFDERR_CORRUPTEDDATA: xbuf->xb_Result = XPKERR_CORRUPTPKD; break;
  419.         case XFDERR_BETTERCPU: xbuf->xb_Result = XPKERR_WRONGCPU; break;
  420.         default: xbuf->xb_Result = XPKERR_UNKNOWN; break;
  421.         }
  422.  
  423. #ifdef DEBUG
  424.   DebugRunTime("XpkRead: xfd failed with %ld", xbuf->xb_Result);
  425. #endif
  426.         return xbuf->xb_Result;
  427.       } /* xfdDecrunchBuffer */
  428.  
  429.       xbuf->xb_Fib.xf_CCur = xbuf->xb_InLen;
  430.       xbuf->xb_Fib.xf_UCur = xbuf->xb_Fib.xf_ULen;
  431.       xbuf->xb_Fib.xf_NLen = 0;
  432.       xbuf->xb_Flags |= XMF_EOF;
  433.  
  434. #ifdef DEBUG
  435.   DebugRunTime("XpkRead: xfd returns %ld", xbuf->xb_Fib.xf_ULen);
  436. #endif
  437.       return (LONG) xbuf->xb_Fib.xf_ULen;
  438.     }
  439.     /********************* Unpack unpacked file *******************/
  440.   case XPKMODE_UPUP:
  441.     {
  442.       ULONG leftlen = xbuf->xb_Fib.xf_ULen - xbuf->xb_Fib.xf_CCur;
  443.  
  444.       if(leftlen > len)
  445.     leftlen = len;
  446.       else
  447.         xbuf->xb_Flags |= XMF_EOF;
  448.  
  449.       if(!(MBUG hookread(xbuf, XIO_READ, buf, leftlen)))
  450.         return xbuf->xb_Result;
  451.  
  452.       xbuf->xb_Fib.xf_CCur += leftlen;
  453.       xbuf->xb_Fib.xf_UCur += leftlen;
  454.       xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen -
  455.         xbuf->xb_Fib.xf_UCur, DEFAULTCHUNKSIZE) + XPK_MARGIN;
  456.  
  457.       return (LONG) leftlen;
  458.     }
  459.   }
  460.  
  461.   return xbuf->xb_Result;
  462. }
  463.  
  464. /**************************************************************************
  465.  *
  466.  *   XpkWrite() - write a chunk to a compressed file
  467.  *
  468.  */
  469.  
  470. ASM(LONG) LIBXpkWrite(REG(a0, struct XpkBuffer *xbuf), REG(a1, STRPTR buf),
  471.     REG(d0, ULONG ulen))
  472. {
  473.   struct Library *XpkSubBase = xbuf->xb_SubBase;
  474.   struct XpkSubParams *xpar;
  475.   struct Headers *head = &xbuf->xb_Headers;
  476.   LONG clen, rclen, outbuflen;
  477.   UWORD end[2] = {0,0}; /* last ULONG of buffer, when not longword bounded */
  478.   UBYTE type;
  479.   STRPTR outbuf;
  480.   MBUGDEF
  481.  
  482. #ifdef DEBUG
  483.   DebugRunTime("XpkWrite: buf %08lx, size %ld", buf, ulen);
  484. #endif
  485.  
  486.   if(!xbuf->xb_FirstChunk)
  487.     xbuf->xb_FirstChunk = ulen;
  488.   if(ulen > xbuf->xb_FirstChunk)
  489.     return (xbuf->xb_Result = XPKERR_BADPARAMS);
  490.  
  491.   if(xbuf->xb_Flags & XMF_NOPACK) /* no packing */
  492.   {
  493.     hookwrite(xbuf, XIO_WRITE, buf, ulen);
  494.     xbuf->xb_Fib.xf_UCur += ulen;
  495.     xbuf->xb_Fib.xf_CCur += ulen;
  496.     xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen - xbuf->xb_Fib.xf_UCur,
  497.       (LONG) xbuf->xb_ChunkSize);
  498.     return xbuf->xb_Result;
  499.   }
  500.  
  501.   /******************* Write the GlobHdr ********************/
  502.   if(!(xbuf->xb_Flags & XMF_GLOBHDR))
  503.   {
  504.     if(!xbuf->xb_Password)
  505.       CopyMem(buf, head->h_Glob.xsh_Initial, Min(16, ulen));
  506.     xbuf->xb_Flags |= XMF_GLOBHDR;
  507.     if(!(MBUG hookwrite(xbuf, XIO_WRITE, &head->h_Glob,
  508.     sizeof(struct XpkStreamHeader))))
  509.       return xbuf->xb_Result;
  510.     xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
  511.   }
  512.  
  513.   /******************* Allocate the buffer *****************/
  514.   outbuflen = ROUNDLONG(ulen + (ulen>>5) + head->h_LocSize) + XPK_MARGIN;
  515.   if(!(outbuf = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, outbuflen)))
  516.     return xbuf->xb_Result;
  517.  
  518.   outbuf += head->h_LocSize;
  519.   /* compress to behind local header. This is needed by mem-out hook! */
  520.  
  521.   if(ulen < xbuf->xb_SubInfo->xi_MinPkInChunk)
  522.     goto copychunk;
  523.  
  524.   /******************* Pack the chunk **********************/
  525.   xpar = &xbuf->xb_PackParam;
  526.   xpar->xsp_InBuf = buf;
  527.   xpar->xsp_InLen = ulen;
  528.   xpar->xsp_OutBuf = outbuf;
  529.   xpar->xsp_OutBufLen = outbuflen - head->h_LocSize;
  530.   xpar->xsp_Number += 1;
  531.   xpar->xsp_Mode = xbuf->xb_PackingMode;
  532.   xpar->xsp_Password = xbuf->xb_Password;
  533.   xpar->xsp_LibVersion = xbuf->xb_SubInfo->xi_LibVersion;
  534.  
  535.   xbuf->xb_Result = XpksPackChunk(xpar);
  536.   xbuf->xb_Flags |= XMF_INITED;
  537.  
  538.   type = XPKCHUNK_PACKED;
  539.   clen = xpar->xsp_OutLen;
  540.  
  541.   if(xbuf->xb_Result == XPKERR_EXPANSION)
  542.   {
  543.     xbuf->xb_Result = 0;
  544. copychunk:
  545.     type = XPKCHUNK_RAW;
  546.     clen = ulen;
  547.     outbuf = buf;
  548.   }
  549.  
  550.   if(xbuf->xb_Result)
  551.     return xbuf->xb_Result;
  552.  
  553.   /******************* Write the chunk **********************/
  554.   head->h_Loc.xch_Word.xchw_Type = type;
  555.   if(head->h_Glob.xsh_Flags & XPKSTREAMF_LONGHEADERS)
  556.   {
  557.     head->h_Loc.xch_Long.xchl_ULen = ulen;
  558.     head->h_Loc.xch_Long.xchl_CLen = clen;
  559.   }
  560.   else
  561.   {
  562.     head->h_Loc.xch_Word.xchw_ULen = (WORD) ulen;
  563.     head->h_Loc.xch_Word.xchw_CLen = (WORD) clen;
  564.   }
  565.  
  566.   if((rclen = clen&3))
  567.   {
  568.     clen -= rclen;
  569.     CopyMem(outbuf+clen, &end, rclen); /* copy the remaining bytes (max 3) */
  570.   }
  571.  
  572.   head->h_Loc.xch_Word.xchw_CChk = cchecksum((ULONG *) outbuf, clen >> 2)
  573.     ^ end[0] ^ end[1];
  574.   /* add the rest bytes to the checksum */
  575.   
  576.   head->h_Loc.xch_Word.xchw_HChk = 0;
  577.   head->h_Loc.xch_Word.xchw_HChk = hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);
  578.  
  579.   if(!(MBUG hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize)))
  580.     return xbuf->xb_Result;
  581.  
  582.   if(!(MBUG hookwrite(xbuf, XIO_WRITE, outbuf, clen)))
  583.     return xbuf->xb_Result;
  584.  
  585.   if(rclen)
  586.   {
  587.     if(!(MBUG hookwrite(xbuf, XIO_WRITE, &end, 4)))
  588.       return xbuf->xb_Result;
  589.     clen += 4;
  590.   }
  591.  
  592.   head->h_Glob.xsh_ULen += ulen;
  593.   
  594.   xbuf->xb_Fib.xf_UCur += ulen;
  595.   xbuf->xb_Fib.xf_CCur += head->h_LocSize + clen;
  596.   xbuf->xb_Fib.xf_NLen = Min(max(xbuf->xb_InLen, head->h_Glob.xsh_ULen) -
  597.     xbuf->xb_Fib.xf_UCur, (LONG) xbuf->xb_ChunkSize);
  598.  
  599.   return xbuf->xb_Result;
  600. }
  601.  
  602. /**************************************************************************
  603.  *
  604.  *   XpkSeek() - move around on a compressed file
  605.  *
  606.  */
  607.  
  608. ASM(LONG) LIBXpkSeek(REG(a0, struct XpkBuffer *xbuf), REG(d0, LONG dist),
  609.     REG(d1, ULONG mode))
  610. {
  611.   xbuf->xb_Result = XPKERR_NOFUNC;
  612.   parsegettags(xbuf);
  613.  
  614.   return xbuf->xb_Result;
  615. }
  616.  
  617. /**************************************************************************
  618.  *
  619.  *   XpkClose() - finish (de)compressing an XPK file
  620.  *
  621.  */
  622.  
  623. ASM(LONG) LIBXpkClose(REG(a0, struct XpkBuffer *xbuf))
  624. {
  625.   struct Library *XpkSubBase = xbuf->xb_SubBase;
  626.  
  627.   if(!xbuf)
  628.     return 0;
  629.  
  630. #ifdef DEBUG
  631.   if(xbuf->xb_Result)
  632.     DebugError("XpkClose: failed (%ld) before XpkClose", xbuf->xb_Result);
  633. #endif
  634.  
  635.   if(xbuf->xb_Format == XPKMODE_PKSTD)
  636.   {
  637.     struct Headers *head = &xbuf->xb_Headers;
  638.     LONG outlen;
  639.  
  640.     if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_GLOBHDR|XMF_NOPACK))
  641.     {
  642.       hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
  643. #ifdef DEBUG
  644.       if(xbuf->xb_Result) DebugError("XpkClose: failed to write globhdr");
  645. #endif
  646.       xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
  647.     }
  648.     if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_NOPACK))
  649.     {
  650.       /******************* Write final chunk header *****************/
  651.       memset(&head->h_Loc, 0, head->h_LocSize);
  652.       head->h_Loc.xch_Word.xchw_Type = XPKCHUNK_END;
  653.       head->h_Loc.xch_Word.xchw_HChk = 0;
  654.       head->h_Loc.xch_Word.xchw_HChk =
  655.         hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);
  656.  
  657.       hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize);
  658. #ifdef DEBUG
  659.       if(xbuf->xb_Result) DebugError("XpkClose: failed to write lochdr");
  660. #endif
  661.       xbuf->xb_Fib.xf_CCur += head->h_LocSize;
  662.       outlen = xbuf->xb_Fib.xf_CCur;
  663.  
  664.       /********************** Write global header *******************/
  665.       hookwrite(xbuf, XIO_SEEK, NULL, -outlen);
  666. #ifdef DEBUG
  667.       if(xbuf->xb_Result) DebugError("XpkClose: failed to reset output");
  668. #endif
  669.  
  670.       head->h_Glob.xsh_Pack = XPK_COOKIE;
  671.       head->h_Glob.xsh_CLen = outlen - 8;
  672.       head->h_Glob.xsh_HChk = 0;
  673.       head->h_Glob.xsh_HChk =
  674.         hchecksum((STRPTR) &head->h_Glob, sizeof(struct XpkStreamHeader));
  675.  
  676.       hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
  677. #ifdef DEBUG
  678.       if(xbuf->xb_Result) DebugError("XpkClose: failed updating globalhdr");
  679. #endif
  680.  
  681.       hookwrite(xbuf, XIO_SEEK, 0, outlen - sizeof(struct XpkStreamHeader));
  682. #ifdef DEBUG
  683.       if(xbuf->xb_Result) DebugError("XpkClose: failed to SEEK to end of output");
  684. #endif
  685.     }
  686.     xbuf->xb_Fib.xf_CLen = xbuf->xb_Fib.xf_CCur;
  687.     xbuf->xb_Fib.xf_ULen = xbuf->xb_Fib.xf_UCur;
  688.  
  689.     /*************************** Shut down *************************/
  690.     if(xbuf->xb_Flags & XMF_INITED)
  691.       XpksPackFree(&xbuf->xb_PackParam);
  692.   }
  693.   else if(xbuf->xb_Format == XPKMODE_UPSTD && xbuf->xb_Flags & XMF_INITED)
  694.     XpksUnpackFree(&xbuf->xb_PackParam);
  695.  
  696.   if(xbuf->xb_RHook)
  697.   {
  698.     hookread(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
  699. #ifdef DEBUG
  700.     if(xbuf->xb_Result) DebugError("XpkClose: failed read ABORT/FREE");
  701. #endif
  702.   }
  703.  
  704.   if(xbuf->xb_WHook)
  705.   {
  706.     hookwrite(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
  707. #ifdef DEBUG
  708.     if(xbuf->xb_Result) DebugError("XpkClose: failed write ABORT/FREE");
  709. #endif
  710.   }
  711.  
  712.   parsegettags(xbuf);        /* Send information to the user */
  713.  
  714. #ifdef DEBUG
  715.     DebugRunTime("XpkClose: InLen %ld, CLen %ld, ULen %ld, ID %.4s", xbuf->xb_InLen,
  716.     xbuf->xb_Fib.xf_CLen, xbuf->xb_Fib.xf_ULen, &xbuf->xb_Fib.xf_ID);
  717. #endif
  718.  
  719.   return freebufs(xbuf);
  720. }
  721.  
  722. #endif /* XPKMASTER_XPKMASTER_C */
  723.  
  724.